/**
 * @file wa_task.c
 *
 */

 /*********************
  *      INCLUDES
  *********************/
#include "wa_task.h"
#include "wa_ll.h"
#include "wa_tick.h"
#include "wa_malloc.h"
/*********************
*      DEFINES
*********************/

/**********************
*      TYPEDEFS
**********************/

/**********************
*  STATIC PROTOTYPES
**********************/

/**********************
*  STATIC VARIABLES
**********************/
static wa_ll top_task_ll;
/**********************
*      MACROS
**********************/

/**********************
*   GLOBAL FUNCTIONS
**********************/

/**
* task module init
*/
void wa_task_module_init(void)
{
	wa_ll_init(&top_task_ll, sizeof(wa_task));
}

/**
* task handle
*/
void wa_task_handle(void)
{
	wa_task* task;
	wa_task* task_next;
	task = wa_ll_get_head(&top_task_ll);
	while (task != NULL)
	{
		if (task->type == WA_TASK_TYPE_TIMER)
		{
			if (task->paused == wa_ok)
			{
				if (wa_tick_get_elap(task->last_run_tick) >= task->period)
				{
					if (task->cb != NULL)
					{
						task->cb((void*)task);
					}
					task->last_run_tick = wa_tick_get();
				}
			}
		}
		else if (task->type == WA_TASK_TYPE_EVENT)
		{
			if (task->evnet_type == WA_TASK_EVENT_OR)
			{
				if ((*(task->event) & task->event_mask)!=0)
				{
					if (task->cb != NULL)
					{
						task->cb((void*)task);
					}
					*(task->event) = 0;
				}
			}
			else if (task->evnet_type == WA_TASK_EVENT_AND)
			{
				if (*(task->event) == task->event_mask)
				{
					if (task->cb != NULL)
					{
						task->cb((void*)task);
					}
					*(task->event) = 0;
				}
			}
		}
		task_next = wa_ll_get_next(&top_task_ll, task);
		task = task_next;
	}
}

/**
* create a task
* @param task
* @param type
*/
wa_task* wa_task_create(wa_task_callback cb, wa_task_type type)
{
	wa_task* task;
	task = wa_ll_add_head(&top_task_ll);
	task->type = type;

	task->cb = cb;
	task->event_mask = 0;
	task->event = NULL;
	task->evnet_type = WA_TASK_EVENT_OR;

	task->period = 0;
	task->last_run_tick = 0;
	task->paused = wa_nok;
	task->param = NULL;

	return task;
}

/**
* delete a task
* @param task
*/
void wa_task_del(wa_task* task)
{
	wa_ll_remove(&top_task_ll, (void*)task);
	wa_free(task);
}

/**
* task set mask event
* @param task
* @param mask
*/
void wa_task_set_mask_evnet(wa_task* task, wa_task_event mask)
{
	if (task->type != WA_TASK_TYPE_EVENT)
	{
		return;
	}
	task->event_mask = mask;
}

/**
* task binding a evnet
* @param task
* @param event
*/
void wa_task_binding_event(wa_task* task, wa_task_event* event)
{
	if (task->type != WA_TASK_TYPE_EVENT)
	{
		return;
	}
	task->event = event;
}

/**
* set task event type
* @param task
* @param type
*/
void wa_task_set_evnet_type(wa_task* task, wa_task_event_type type)
{
	if (task->type != WA_TASK_TYPE_EVENT)
	{
		return;
	}
	task->evnet_type = type;
}

/**
* set task timer period
* @param task
* @param period
*/
void wa_task_set_timer_period(wa_task* task, uint32_t period)
{
	if (task->type != WA_TASK_TYPE_TIMER)
	{
		return;
	}
	task->period = period;
}

/**
* start task timer
* @param task
*/
void wa_task_start_timer(wa_task* task)
{
	if (task->type != WA_TASK_TYPE_TIMER)
	{
		return;
	}
	task->last_run_tick = wa_tick_get();
	task->paused = wa_ok;
}

/**
* stop task timer
* @param task
*/
void wa_task_stop_timer(wa_task* task)
{
	if (task->type != WA_TASK_TYPE_TIMER)
	{
		return;
	}
	task->paused = wa_nok;
}

/**
* check task timer is start
* @param task
*/
wa_result wa_task_timer_is_start(wa_task* task)
{
	return task->paused;
}

/**
* set task param
* @param task
* @param param
*/
void wa_task_set_param(wa_task* task, void* param)
{
	task->param = param;
}

/**
* event set bit
* @param event
* @param mask
*/
void wa_task_event_set_bit(wa_task_event* event, wa_task_event mask)
{
	*event |= mask;
}

/**
* event clear bit
* @param event
* @param mask
*/
void wa_task_event_clear_bit(wa_task_event* event, wa_task_event mask)
{
	*event &= ~mask;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
